1 module project.gen;
2 import std.path:buildNormalizedPath;
3 import std.file;
4 import std.format:format;
5 import std.process;
6 import std.array:join,split,array;
7 
8 struct TemplateInfo
9 {
10 	string initMethod=q{
11 	},
12 	update="",
13 	render=q{
14 		drawText("You can start using the D Scripting API Here!", 400, 300, 2.0, HipColor.white,
15 			HipTextAlign.center
16 		);
17 	},
18 	dispose="";
19 }
20 
21 struct DubProjectInfo
22 {
23 	string author = "HipremeEngine";
24 	string projectName = "Hipreme Engine Test";
25 	string desc = "Hipreme Engine test scene";
26 }
27 
28 string generateCodeTemplate(TemplateInfo info = TemplateInfo())
29 {
30 	return format!q{
31 module gamescript.entry;
32 import hip.api;
33 
34 /**
35 *	Call `dub` to generate the DLL, after that, just execute `dub -c run` for starting your project
36 */
37 class MainScene : AScene, IHipPreloadable
38 {
39 	mixin Preload;
40 
41 	/** Constructor */
42 	override void initialize()
43 	{
44 		%s
45 	}
46 	/** Called every frame */
47 	override void update(float dt)
48 	{
49 		%s
50 	}
51 	/** Renderer only, may not be called every frame */
52 	override void render()
53 	{
54 		%s
55 	}
56 	/** Pre destroy */
57 	override void dispose()
58 	{
59 		%s
60 	}
61 	override void onResize(uint width, uint height){}
62 }
63 
64 mixin HipEngineMain!MainScene;
65 	}(info.initMethod, info.update, info.render, info.dispose);
66 }
67 
68 
69 string escapeWindowsPathSep(string input)
70 {
71 	string output = "";
72 	foreach(ch; input)
73 		if(ch == '\\')
74 			output~="\\\\";
75 		else
76 			output~= ch;
77 	return output;
78 }
79 
80 string generateDubProject(DubProjectInfo info)
81 {
82 	import std.conv;
83 	import std.uni:toLower;
84 	import std.algorithm:map;
85 	dstring outputName = info.projectName.split(" ").join("_").array;
86 	dstring name = outputName.map!(character => character.toLower).array;
87 
88 	return format!`{
89 	"$schema": "https://raw.githubusercontent.com/Pure-D/code-d/master/json-validation/dub.schema.json",
90 	"authors": ["%s"],
91 	"description" : "%s",
92 	"license": "proprietary",
93 	"targetName" : "%s",
94 	"name" : "%s",
95 	"engineModules": [
96 		"util",
97 		"timer",
98 		"tween",
99 		"data",
100 		"math",
101 		"game2d"
102 	],
103 	"stringImportPaths": ["#PROJECT/ct_assets"],
104 	"dflags-ldc": ["--disable-verify", "--oq"],
105 	"plugins": {
106 		"getmodules": "#HIPREME_ENGINE/tools/internal/plugins/getmodules"
107 	},
108 	"preBuildPlugins": {
109 		"getmodules": ["#PROJECT/ct_assets/scriptmodules.txt"]
110 	},
111 	"configurations":
112 	[
113 		{
114 			"name" : "script",
115 			"targetType": "dynamicLibrary",
116 			"dflags-ldc": ["-link-defaultlib-shared=true"],
117 			"dependencies": {
118 				"hipengine_api": {"path": "#HIPREME_ENGINE/api"}
119 			},
120 			"lflags-windows-ldc": [
121                 "/WHOLEARCHIVE:hipengine_api_bindings",
122                 "/WHOLEARCHIVE:hipengine_api_interfaces"
123             ],
124 			"versions": ["ScriptAPI"],
125 			"lflags-windows": ["/WX"]
126 		},
127 		{
128 			"name": "release",
129 			"targetType": "executable",
130 			"dependencies": {
131 				"hipreme_engine": {"path": "#HIPREME_ENGINE"}
132 			},
133 			"subConfigurations": {
134 				"hipreme_engine": "desktop-release"
135 			}
136 		},
137 		{
138 			"name": "release-wasm",
139 			"targetType": "executable",
140 			"dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}},
141 			"subConfigurations": {
142 				"hipreme_engine": "wasm",
143 				"game2d": "direct"
144 			}
145 		},
146 		{
147 			"name": "appleos",
148 			"targetType": "staticLibrary",
149 			"dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}},
150 			"subConfigurations": {"hipreme_engine": "appleos", "game2d": "direct"}
151 		},
152 		{
153 			"name": "ios",
154 			"targetType": "staticLibrary",
155 			"dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}},
156 			"subConfigurations": {"hipreme_engine": "ios", "game2d": "direct"}
157 		},
158 		{
159 			"name": "android",
160 			"targetType": "dynamicLibrary",
161 			"dependencies": { "hipreme_engine": {"path": "#HIPREME_ENGINE"} },
162 			"subConfigurations": {"hipreme_engine": "android", "game2d": "direct"}
163 		},
164 		{
165 			"name": "uwp",
166 			"dflags-ldc": ["-link-defaultlib-shared=true"],
167 			"targetType": "dynamicLibrary",
168 			"dependencies": {"hipreme_engine": {"path": "#HIPREME_ENGINE"}},
169 			"subConfigurations": {"hipreme_engine": "uwp", "game2d": "direct"}
170 		},
171 		{
172 			"name": "psvita",
173 			"targetType": "staticLibrary",
174 			"subConfigurations": {"hipreme_engine": "psvita", "game2d": "direct"}
175 		},
176 		{
177 			"name": "run",
178 			"targetType": "dynamicLibrary",
179 			"lflags-windows": [
180 				"/WX"
181 			],
182 			"postGenerateCommands-windows": ["cd /d #HIPREME_ENGINE && redub -c script -- $PACKAGE_DIR"],
183 			"postGenerateCommands-linux": ["cd #HIPREME_ENGINE && redub -c script -- $PACKAGE_DIR"]
184 		}
185 	]
186 }
187 `(info.author, info.desc, outputName, name);
188 }
189 
190 string generateReadmeContent(string projectName)
191 {
192 	return "# "~projectName~"\n"~projectName~" is made using Hipreme Engine.\n" ~
193 		"## Building Instructions \n" ~
194 		"1. Run `dub hipreme_engine:hbuild`\n" ~
195 		"2. Select 'Select Game'\n" ~
196 		"3. Select the folder containing "~projectName~"\n"~
197 		"4. Now you can simply choose the platform to build for";
198 }
199 
200 string generateVSCodeDebuggerLaunch(string enginePath)
201 {
202 	import std.system;
203 	string hipEnginePath = enginePath;
204 	string hipEngineExecutable = (buildNormalizedPath(hipEnginePath, "bin", "desktop", "hipreme_engine") ~ ((os == OS.linux) ? "" : ".exe")).escapeWindowsPathSep;
205 	return format!q{
206 {
207     // Use IntelliSense to learn about possible attributes.
208     // Hover to view descriptions of existing attributes.
209     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
210 	// Auto Generated by HipremeEngine project generator.
211 	// Automatically handle SIGUSR1 and SIGUSR2 as they are currently used in semaphore.wait
212     "version": "0.2.0",
213     "configurations": [
214         {
215             "name": "Debug",
216             "type": "gdb",
217             "request": "launch",
218             "target": "%s",
219             "cwd": "${workspaceRoot}",
220             "arguments": "${workspaceRoot}",
221             "debugger_args": [
222                 "-ex", "handle SIGUSR1 noprint",
223                 "-ex", "handle SIGUSR2 noprint"
224             ]
225         }
226     ]
227 }
228 }(hipEngineExecutable);
229 }
230 
231 import commons;
232 bool generateProject(ref Terminal t, string projectPath, string enginePath,
233 DubProjectInfo dubInfo, TemplateInfo templateInfo)
234 {
235 	string dubProj = generateDubProject(dubInfo);
236 	string codeTemplate = generateCodeTemplate(templateInfo);
237 	string debugLauncher = generateVSCodeDebuggerLaunch(enginePath);
238 
239 	try
240 	{
241 	    //Project folder
242 		t.writeln("Creating project folder");
243 		mkdirRecurse(projectPath);
244 		//Source Folder
245 		t.writeln("Creating scripts folder");
246 		mkdirRecurse(buildNormalizedPath(projectPath, "source", "gamescript"));
247 		//Assets Folder
248 		t.writeln("Creating assets folder");
249 		mkdirRecurse(buildNormalizedPath(projectPath, "assets"));
250 		//Compilation Time Assets folder
251 		t.writeln("Creating Compilation Time Assets folder");
252 		mkdirRecurse(buildNormalizedPath(projectPath, "ct_assets"));
253 		//VSCode Folder
254 		t.writeln("Creating vscode folder");
255 		mkdirRecurse(buildNormalizedPath(projectPath, ".vscode"));
256 
257 		t.writeln("Writing code template for gamescript/entry.d");
258 		std.file.write(buildNormalizedPath(projectPath, "source", "gamescript", "entry.d"), codeTemplate);
259 		t.writeln("Writing dub.template.json");
260 		std.file.write(buildNormalizedPath(projectPath, "dub.template.json"), dubProj);
261 		t.writeln("Writing README.md");
262 		std.file.write(buildNormalizedPath(projectPath, "README.md"), generateReadmeContent(dubInfo.projectName));
263 		t.writeln("Writing VSCode debug launcher");
264 		std.file.write(buildNormalizedPath(projectPath, ".vscode", "launch.json"), debugLauncher);
265 
266 		t.writeln("Writing .gitignore");
267 		std.file.write(buildNormalizedPath(projectPath, ".gitignore"),  q{
268 dub.selections.json
269 dub.json
270 .DS_Store
271 .dub
272 .history
273 .vs
274 bin
275 *.exe
276 *.exp
277 *.lnk
278 *.dll
279 *.dll_hiptempdll
280 *.so
281 *.lib
282 *.a
283 *.pdb
284 });
285 	}
286 	catch(Exception e)
287 	{
288 		t.writelnError(e.toString);
289 		return false;
290 	}
291 	import commons;
292 	return writeTemplate(t, projectPath, enginePath);
293 }